﻿using CCManger.Common;
using CCManger.Common.Coder;
using CCManger.Common.Message;
using DotNetty.Codecs;
using DotNetty.Handlers.Logging;
using DotNetty.Handlers.Timeout;
using DotNetty.Handlers.Tls;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using DotNetty.Transport.Libuv;
using Serilog;
using System;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace CCManger.Server
{
    internal class Program
    {
        private static async Task RunServerAsync()
        {
            //ExampleHelper.SetConsoleLogger();

            //主线程 用于接受连接
            var bossGroup = new MultithreadEventLoopGroup(1);
            //工作线程 用于测试执行通讯信息
            var workerGroup = new MultithreadEventLoopGroup();
            X509Certificate2 tlsCertificate = null;
            //if (ServerSettings.IsSsl)
            //{
            //    tlsCertificate = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
            //}
            try
            {
                var bootstrap = new ServerBootstrap();
                bootstrap
                    .Group(bossGroup, workerGroup)
                    .Channel<TcpServerSocketChannel>()
                    .Option(ChannelOption.SoBacklog, 100)
                    .Handler(new LoggingHandler("LSTN"))
                    .ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;
                        if (tlsCertificate != null)
                        {
                            pipeline.AddLast(TlsHandler.Server(tlsCertificate));
                        }
                        pipeline.AddLast(new LoggingHandler("CONN"));
                        pipeline.AddLast(new DiscardServerHandler());
                    }));

                IChannel bootstrapChannel = await bootstrap.BindAsync(23456);

                Console.ReadLine();

                await bootstrapChannel.CloseAsync();
            }
            finally
            {
                Task.WaitAll(bossGroup.ShutdownGracefullyAsync(), workerGroup.ShutdownGracefullyAsync());
            }
        }

        private static async Task RunServerAsync1()
        {
            IEventLoopGroup bossGroup;
            IEventLoopGroup workerGroup;

            if (CCManagerHelper.ServerSettings.UseLibuv)
            {
                var dispatcher = new DispatcherEventLoopGroup();
                bossGroup = dispatcher;
                workerGroup = new WorkerEventLoopGroup(dispatcher);
            }
            else
            {
                bossGroup = new MultithreadEventLoopGroup(1);
                workerGroup = new MultithreadEventLoopGroup();
            }

            X509Certificate2 tlsCertificate = null;
            if (CCManagerHelper.ServerSettings.IsSsl)
            {
                //tlsCertificate = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
            }
            try
            {
                var bootstrap = new ServerBootstrap();
                bootstrap.Group(bossGroup, workerGroup);

                if (CCManagerHelper.ServerSettings.UseLibuv)
                {
                    bootstrap.Channel<TcpServerChannel>();
                }
                else
                {
                    bootstrap.Channel<TcpServerSocketChannel>();
                }

                bootstrap
                    .Option(ChannelOption.SoBacklog, 100) // 设置网络IO参数等，这里可以设置很多参数，当然你对网络调优和参数设置非常了解的话，你可以设置，或者就用默认参数吧
                    .Option(ChannelOption.SoKeepalive, true)//保持连接
                    .Handler(new LoggingHandler("SRV-LSTN"))
                    .ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;
                        if (tlsCertificate != null)
                        {
                            pipeline.AddLast("tls", TlsHandler.Server(tlsCertificate));
                        }
                        pipeline.AddLast(new LoggingHandler("SRV-CONN"));
                        pipeline.AddLast("framing-enc", new LengthFieldPrepender(2));
                        pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(ushort.MaxValue, 0, 2, 0, 2));

                        pipeline.AddLast("echo", new EchoServerHandler());
                    }));

                IChannel boundChannel = await bootstrap.BindAsync(CCManagerHelper.ServerSettings.Port);

                Console.ReadLine();

                await boundChannel.CloseAsync();
            }
            finally
            {
                await Task.WhenAll(
                    bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)),
                    workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
            }
        }

        private static async Task MainRunServerAsync()
        {
            //ExampleHelper.SetConsoleLogger();

            //主线程 用于接受连接
            var bossGroup = new MultithreadEventLoopGroup(1);
            //工作线程 用于测试执行通讯信息
            var workerGroup = new MultithreadEventLoopGroup();
            X509Certificate2 tlsCertificate = null;
            //if (ServerSettings.IsSsl)
            //{
            //    tlsCertificate = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password");
            //}
            try
            {
                var bootstrap = new ServerBootstrap();
                bootstrap
                    .Group(bossGroup, workerGroup)
                    .Channel<TcpServerSocketChannel>()
                    .Option(ChannelOption.SoBacklog, 100)
                    //.Option(ChannelOption.SoKeepalive, true)//保持连接
                    //.Handler(new LoggingHandler("LSTN"))
                    .ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        //工作线程连接器 是设置了一个管道，服务端主线程所有接收到的信息都会通过这个管道一层层往下传输
                        //同时所有出栈的消息 也要这个管道的所有处理器进行一步步处理
                        IChannelPipeline pipeline = channel.Pipeline;
                        if (tlsCertificate != null)
                        {
                            pipeline.AddLast(TlsHandler.Server(tlsCertificate));
                        }
                        //配置编码解码器
                        pipeline.AddLast(new CommonEncoder<Common.Message.Message>());
                        pipeline.AddLast(new CommonDecoder());
                        // IdleStateHandler 心跳
                        //服务端为读IDLE
                        pipeline.AddLast(new IdleStateHandler(15, 0, 0));//第一个参数为读，第二个为写，第三个为读写全部
                                                                         //业务handler ，这里是实际处理业务的Handler
                        HelloServerHandler ServerHandler = new HelloServerHandler
                        {
                            _Socket = pipeline.FirstContext()
                        };
                        ServerHandler.MessageReceived += ServerHandler_MessageReceivedAsync;
                        ServerHandler.MessageSend += ServerHandler_MessageSendAsync;
                        ServerHandler.MessageGroupSend += ServerHandler_MessageGroupSend;
                        pipeline.AddLast(ServerHandler);
                    }));
                IChannel bootstrapChannel = await bootstrap.BindAsync(CCManagerHelper.ServerSettings.Port);

                Console.ReadLine();

                await bootstrapChannel.CloseAsync();
            }
            finally
            {
                Task.WaitAll(bossGroup.ShutdownGracefullyAsync(), workerGroup.ShutdownGracefullyAsync());
            }
        }

        private async static void ServerHandler_MessageGroupSend(object sender, MessageEventArgs e)
        {
            try
            {
                var clients = sender as HelloServerHandler;
                await Task.Run(() => { clients.GroupSendData(e.CMD); });
            }
            catch (Exception ex)
            {
                Log.Error(ex, "群发消息");
            }
        }

        private static async void ServerHandler_MessageSendAsync(object sender, MessageEventArgs e)
        {
            try
            {
                var client = sender as HelloServerHandler;
                await Task.Run(() => { client.SendData(e.CMD); });
            }
            catch (Exception ex) { Log.Error(ex, "单独发消息"); }
        }

        private static async void ServerHandler_MessageReceivedAsync(object sender, MessageEventArgs e)
        {
            try
            {
                var client = sender as HelloServerHandler;
                await Task.Run((Action)(() =>
                {
                    switch (e.CMD.Command)
                    {
                        case COMMAND.Message:
                            Console.WriteLine($"解码器方式，从客户端接收:{e.CMD.Content}:{DateTime.Now}");
                            ServerHandler_MessageSendAsync((object)sender, (MessageEventArgs)new MessageEventArgs((IMessage)new Message { Command = COMMAND.Message, Content = "服务端接收到后返回，我是服务端" }));
                            return;
                        case COMMAND.ClientToServer:
                            Log.Debug("收到消息!{@INfo}",e.CMD);
                            return;
                        default:
                            Console.WriteLine($"解码器方式，客户端心跳:{e.CMD.Content}");
                            ServerHandler_MessageSendAsync((object)sender, (MessageEventArgs)new MessageEventArgs((IMessage)new Message { Command = COMMAND.Message, Content = "服务端接收到心跳连接" }));
                            return;
                    }
                }));
            }
            catch (Exception ex) { }
        }

        private static void Main(string[] args)
        {
            try
            {
                CCManagerHelper.InitServerSerilog();//配置log
                Log.Information("服务配置信息{@ServerSettings}", CCManagerHelper.ServerSettings);
                MainRunServerAsync().Wait();
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Main");
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
    }
}